/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package hxg.http.server.handler.impl;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
import hxg.http.server.HttpPath;
import hxg.http.server.NamedRequestHandler;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.net.telnet.TelnetClient;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.http.nio.protocol.HttpAsyncExchange;
import org.apache.http.protocol.HttpContext;

/**
 *
 * @author hxg
 */
@HttpPath(name = "/rc")
public class RemoteShellHandler extends NamedRequestHandler {

    private static final UserInfo defaultUserInfo = new UserInfo() {

        @Override
        public String getPassphrase() {
            return null;
        }

        @Override
        public String getPassword() {
            return null;
        }

        @Override
        public boolean promptPassword(String arg0) {
            return false;
        }

        @Override
        public boolean promptPassphrase(String arg0) {
            return false;
        }

        @Override
        public boolean promptYesNo(String arg0) {
            return true;
        }

        @Override
        public void showMessage(String arg0) {
        }
    };
    private static final Map<String, RemoteStreamClient> remoteShellMap = new ConcurrentHashMap<>();

    @Override
    public void handle(HttpRequest t, HttpAsyncExchange hae, HttpContext hc) throws HttpException, IOException {
        Map<String, List<String>> mp = super.getParamsModeGet(t);
        if (mp.containsKey("token")) {
            String token = mp.get("token").get(0);
            System.out.println("Token=" + token);
            RemoteStreamClient client = remoteShellMap.get(token);
            if (client != null) {
                System.out.println("有效Token," + token);
                if (mp.containsKey("cmd")) {
                    String cmd = URLDecoder.decode(mp.get("cmd").get(0),"utf8");
                    System.out.println("发送命令[os前]:" + cmd);
                    OutputStream os = client.getOutputStream();
                    os.write(cmd.getBytes());
                    os.write("\r".getBytes());
                    os.flush();
                    System.out.println("发送命令[os后]:" + cmd);
                    hae.getResponse().setEntity(new NStringEntity("命令[" + cmd + "]已发送", "UTF-8"));
                    hae.submitResponse();
                } else if (mp.containsKey("next")) {
                    //String len = mp.get("next").get(0);
                    System.out.println("刷新数据");

                    String val = client.getData();
                    hae.getResponse().setEntity(new NStringEntity(val, "UTF-8"));
                    hae.submitResponse();
                } else if (mp.containsKey("exit")) {
                    System.out.println("退出");
                    client.disconnect();
                    hae.getResponse().setEntity(new NStringEntity("Closed", "UTF-8"));
                    hae.submitResponse();
                }
            }
        } else {
            String ip;
            String username;
            String password;
            if (mp.containsKey("ip") && mp.containsKey("mode")) {
                try {
                    ip = mp.get("ip").get(0);
                    String mode = mp.get("mode").get(0);
                    String token = createToken();
                    while (remoteShellMap.containsKey(token)) {
                        token = createToken();
                    }
                    if (mode.toLowerCase().equals("telnet")) {
                        TelnetClient tc = new TelnetClient();
                        tc.connect(ip);
                        remoteShellMap.put(token, new RemoteStreamClient(token, tc));
                    }
                    if (mode.toLowerCase().equals("ssh2") && mp.containsKey("username") && mp.containsKey("password")) {
                        username = mp.get("username").get(0);
                        password = mp.get("password").get(0);
                        try {
                            Channel cl = createChannel(ip, 22, username, password);
                            remoteShellMap.put(token, new RemoteStreamClient(token, cl));
                        } catch (JSchException ex) {
                            Logger.getLogger(RemoteShellHandler.class.getName()).log(Level.SEVERE, null, ex);
                            hae.getResponse().setEntity(new NStringEntity("-1", "UTF-8"));
                            hae.submitResponse();
                        }
                    }
                    hae.getResponse().setEntity(new NStringEntity(token, "UTF-8"));
                    hae.submitResponse();
                } catch (NoSuchAlgorithmException ex) {
                    Logger.getLogger(RemoteShellHandler.class.getName()).log(Level.SEVERE, null, ex);
                }
            } else {
                hae.getResponse().setEntity(new NStringEntity("缺失参数,请检查参数是否完整", "UTF-8"));
                hae.submitResponse();
            }

        }
    }

    public final static String createToken() throws NoSuchAlgorithmException {
        MessageDigest disg = MessageDigest.getInstance("SHA1");
        StringBuilder sb = new StringBuilder();
        byte[] bytes = disg.digest(String.valueOf(System.nanoTime()).getBytes());
        for (int i = 0; i < bytes.length; i++) {
            String ts = Integer.toHexString(bytes[i] & 0xff);
            if (ts.length() == 1) {
                sb.append("0").append(ts);
            } else if (ts.length() == 2) {
                sb.append(ts);
            }
        }
        //Token与时间有关，
        return sb.toString();
    }

    private Channel createChannel(String ip, int port, String username, String password) throws JSchException {
        JSch jsch = new JSch();
        Session session;
        Channel channel;
        session = jsch.getSession(username, ip, port);
        session.setPassword(password);
        session.setUserInfo(defaultUserInfo);
        session.connect(5000);
        channel = session.openChannel("shell");
        //channel.setOutputStream(System.out);
        channel.connect(5000);
        return channel;
    }

}
